package com.quanyue.music.user.service.impl;

import com.quanyue.auto.cache.CacheService;
import com.quanyue.auto.web.Principal;
import com.quanyue.music.domain.constant.CacheConstants;
import com.quanyue.music.domain.constant.FMChannel;
import com.quanyue.music.domain.constant.RechargeRuleId;
import com.quanyue.music.domain.entity.FmVip;
import com.quanyue.music.domain.entity.User;
import com.quanyue.music.file.api.ListenRecordService;
import com.quanyue.music.user.mapper.UserMapper;
import com.quanyue.music.user.mapper.VIPMapper;
import com.quanyue.music.user.service.UserService;
import com.quanyue.music.user.type.UserDetail;
import com.quanyue.music.user.type.UserHowLong;
import com.shzisg.mybatis.mapper.page.Page;
import com.shzisg.mybatis.mapper.page.PageRequest;
import entity.UserRecord;
import jxl.Workbook;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {
    private final String path = "/opt/music/admin/server/static/dist/excel/";
    //    private final String path = "D:\\test\\user\\";
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private VIPMapper vipMapper;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private ListenRecordService listenRecordService;
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public User findByName(String name) {
        return userMapper.findByName(name);
    }

    @Override
    public User findByOpenId(String openId) {
        return userMapper.findByOpenId(openId);
    }

    @Override
    public User findById(String id) {
        return userMapper.findOne(id);
    }

    @Override
    public void updateEmail(String email, String userId) {
        userMapper.updateEmail(email, userId);
    }

    @Override
    @Transactional
    public User add(User user) {
        user.setCreateTime(LocalDateTime.now());
        user.setModifyTime(user.getCreateTime());
        userMapper.insert(user);
        // 赠送两个月会员
        FmVip fmVip = new FmVip();
        fmVip.setUserId(user.getId());
        fmVip.setRechargeRule(RechargeRuleId.DEFAULTRULE_TWO);
        fmVip.setStartTime(LocalDateTime.now());
        fmVip.setEndTime(LocalDateTime.now().plusMonths(2));
        fmVip.setDelFlag(false);
        vipMapper.insert(fmVip);
        return user;
    }

    @Override
    public void update(User user) {
        userMapper.updateSelective(user);
    }

    @Override
    public Page <UserDetail> findUsers(PageRequest request) {
        request.setAsc(false);
        request.setOrderBy("u.create_time");
        Page <UserDetail> userDetailPage = userMapper.findUserDetailPage(request);
        this.infoHandle(userDetailPage.getContent());
        return userDetailPage;
    }

    private List <UserDetail> infoHandle(List <UserDetail> userDetails) {
        List <String> userIdList = new ArrayList <>();
        userDetails.forEach(userDetail -> {
            userDetail.setVip(false);
            if (userDetail.getEndTime() != null) userDetail.setVip(true);
            userIdList.add(userDetail.getId());
        });
        Future <List <UserRecord>> longFutures = listenRecordService.findLongByChannel(FMChannel.CHANNEL_ONE, userIdList);
        Future <List <UserRecord>> twoFutures = listenRecordService.findLongByChannel(FMChannel.CHANNEL_TWO, userIdList);
        try {
            Map <String, Long> longOneMap = longFutures.get().stream()
                    .collect(Collectors.toMap(UserRecord::getUserId, UserRecord::getCount));
            Map <String, Long> longTwoMap = twoFutures.get().stream()
                    .collect(Collectors.toMap(UserRecord::getUserId, UserRecord::getCount));
            for (UserDetail userDetail : userDetails) {
                userDetail.setHowLongOne(longOneMap.getOrDefault(userDetail.getId(), 0L));
                userDetail.setHowLongTwo(longTwoMap.getOrDefault(userDetail.getId(), 0L));
            }
        } catch (Exception e) {
            log.error("Error:", e);
        }
        return userDetails;
    }

    @Override
    public String excelUser() {
        List <UserDetail> userDetails = this.infoHandle(userMapper.findUserDetail());
        return this.createExcel(userDetails);
    }

    @Override
    public String excelUserEveryday(String date) {
        List <UserHowLong> userHowLongs = userMapper.findUserHowLong(LocalDate.parse(date));
        return this.createExcelEveryday(userHowLongs);
    }

    @Override
    public Boolean getAddressByIP(String ip) {
        // 这里调用pconline的接口
        String urlStr = "http://ip.taobao.com/service/getIpInfo.php";
        // 从http://whois.pconline.com.cn取得IP所在的省市区信息
        String returnStr = this.getResult(urlStr, "ip=" + ip, "utf-8");
        if (returnStr != null) {
            if (returnStr.equals("true"))
                return true;
            JSONObject json = new JSONObject(returnStr);
            JSONObject body = json.getJSONObject("data");
            log.info("body: {}", body);
            String country = body.getString("country");
            log.info("用户所在的国家: {}", country);
            if (country.equals("美国") || country.equals("加拿大"))
                return true;
        }
        return false;
    }

    private String createExcelEveryday(List <UserHowLong> userHowLongs) {
        try {
            String fileName = "How_Long.xls";
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            //  打开文件
            WritableWorkbook book = Workbook.createWorkbook(new File(path, fileName));
            //  生成名为“第一页”的工作表，参数0表示这是第一页
            WritableSheet sheet = book.createSheet(" 第一页 ", 0);
            int row = 0;
            for (UserHowLong result : userHowLongs) {
                int column = 0;
                Long howLog = result.getHowLong() == null ? 0 : result.getHowLong();
                sheet.addCell(new Label(column++, row, result.getUserId()));
                sheet.addCell(new Label(column++, row, String.valueOf(howLog)));
                ++row;
            }
            //  写入数据并关闭文件
            book.write();
            book.close();
            return "/excel/" + fileName;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private String createExcel(List <UserDetail> userDetails) {
        try {
            String fileName = "USER.xls";
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            //  打开文件
            WritableWorkbook book = Workbook.createWorkbook(new File(path, fileName));
            //  生成名为“第一页”的工作表，参数0表示这是第一页
            WritableSheet sheet = book.createSheet(" 第一页 ", 0);

            //  将定义好的单元格添加到工作表中  在Label对象的构造子中指名单元格位置是第一列第一行(0,0)
            sheet.addCell(new Label(0, 0, "昵称"));
            sheet.addCell(new Label(1, 0, "用户ID"));
            sheet.addCell(new Label(2, 0, "性别"));
            sheet.addCell(new Label(3, 0, "VIP"));
            sheet.addCell(new Label(4, 0, "内部员工"));
            sheet.addCell(new Label(5, 0, "收听总时长"));
            sheet.addCell(new Label(6, 0, "A收听时长"));
            sheet.addCell(new Label(7, 0, "B收听时长"));
            sheet.addCell(new Label(8, 0, "推荐好友数"));
            sheet.addCell(new Label(9, 0, "二维码"));
            sheet.addCell(new Label(10, 0, "登录次数"));
            sheet.addCell(new Label(11, 0, "首次登录"));
            sheet.addCell(new Label(12, 0, "到期时间"));
            sheet.addCell(new Label(13, 0, "充值次数"));
            sheet.addCell(new Label(14, 0, "累计金额"));
            sheet.addCell(new Label(15, 0, "用户邮箱"));

            int row = 1;
            for (UserDetail result : userDetails) {
                int column = 0;
                Long howLongOne = result.getHowLongOne() == null ? 0 : result.getHowLongOne();
                Long howLongTwo = result.getHowLongTwo() == null ? 0 : result.getHowLongTwo();
                Integer validCount = result.getValidCount() == null ? 0 : result.getValidCount();
                BigDecimal totalPrice = result.getTotalPrice() == null ? BigDecimal.ZERO : result.getTotalPrice();

                sheet.addCell(new Label(column++, row, result.getNickName()));
                sheet.addCell(new Label(column++, row, result.getId()));
                sheet.addCell(new Label(column++, row, result.getSex().equals(1) ? "男" : "女"));
                sheet.addCell(new Label(column++, row, result.getVip().toString()));
                sheet.addCell(new Label(column++, row, result.getInsideUser().toString()));
                sheet.addCell(new Label(column++, row, String.valueOf((howLongOne + howLongTwo))));
                sheet.addCell(new Label(column++, row, String.valueOf(howLongOne)));
                sheet.addCell(new Label(column++, row, String.valueOf(howLongTwo)));
                sheet.addCell(new Label(column++, row, String.valueOf(validCount)));
                sheet.addCell(new Label(column++, row, result.getQyCode()));
                sheet.addCell(new Label(column++, row, String.valueOf(result.getLoginNum())));
                sheet.addCell(new Label(column++, row, result.getCreateTime().toString()));
                sheet.addCell(new Label(column++, row, String.valueOf(result.getEndTime())));
                sheet.addCell(new Label(column++, row, String.valueOf(result.getRechargeCount())));
                sheet.addCell(new Label(column++, row, String.valueOf(totalPrice)));
                sheet.addCell(new Label(column++, row, result.getEmail()));
                ++row;
            }
            //  写入数据并关闭文件
            book.write();
            book.close();
            return "/excel/" + fileName;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private String getResult(String urlStr, String content, String encoding) {
        URL url = null;
        HttpURLConnection connection = null;
        try {
            url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(8000);
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.connect();
            DataOutputStream out = new DataOutputStream(connection
                    .getOutputStream());
            out.writeBytes(content);
            out.flush();
            out.close();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    connection.getInputStream(), encoding));
            StringBuffer buffer = new StringBuffer();
            String line = "";
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            reader.close();
            return buffer.toString();
        } catch (IOException e) {
            log.info("超时：{}", content);
            return "true";
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    @PostConstruct
    public void initSessionCache() {
        Map <String, Principal> map = new ConcurrentHashMap <>();
        cacheService.put(CacheConstants.SESSION_CACHE.name(), map);
    }
}
